package cn.piesat.service.impl;

import cn.piesat.dao.*;
import cn.piesat.dto.PiesatResourceInfoDTO;
import cn.piesat.mapper.RoleMapper;
import cn.piesat.util.JedisUtils;
import cn.piesat.util.PageUtil;
import cn.piesat.vo.role.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.piesat.dto.PiesatRoleInfoDTO;
import cn.piesat.dto.PiesatRoleMenuDTO;
import cn.piesat.dto.PiesatRoleResourceDTO;
import cn.piesat.service.intf.RoleService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * 角色服务逻辑实现
 *
 * @author xhl
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private PiesatRoleInfoDAO piesatRoleInfoDAO;
    @Autowired
    private PiesatRoleMenuDAO piesatRoleMenuDAO;
    @Autowired
    private PiesatRoleResourceDAO piesatRoleResourceDAO;
    @Autowired
    private PiesatRoleUserDAO piesatRoleUserDAO;
    @Autowired
    private PiesatResourceInfoDAO piesatResourceInfoDAO;


    @Override
    public Map<String, String> add(AddRoleVO vo) {
        Map<String,String> resultMap = new HashMap<>();
        PiesatRoleInfoDTO dto = piesatRoleInfoDAO.findByName(vo.getName());
        if(dto !=null){
            resultMap.put("success","false");
            resultMap.put("message","添加失败，角色名称已存在");
            return resultMap;
        }
        PiesatRoleInfoDTO dto1 = piesatRoleInfoDAO.findByMark(vo.getMark());
        if(dto1 !=null){
            resultMap.put("success","false");
            resultMap.put("message","添加失败，角色标识已存在");
            return resultMap;
        }
        PiesatRoleInfoDTO piesatRoleInfoDTO = RoleMapper.INSTANCE.addRoleVoToRoleDto(vo);
        piesatRoleInfoDTO.setCreateTime(new Date());
        piesatRoleInfoDAO.save(piesatRoleInfoDTO);
        resultMap.put("success","true");
        resultMap.put("message","添加成功");
        return resultMap;
    }

    @Override
    public Map<String, String> update(UpdateRoleVO vo) {
        Map<String,String> resultMap = new HashMap<>();
        PiesatRoleInfoDTO piesatRoleInfoDTO = RoleMapper.INSTANCE.updateRoleVoToRoleDto(vo);
        piesatRoleInfoDTO.setCreateTime(new Date());
        piesatRoleInfoDAO.save(piesatRoleInfoDTO);
        resultMap.put("success","true");
        resultMap.put("message","修改成功");
        return resultMap;
    }

    @Override
    public PiesatRoleInfoDTO getOne(String id) {
        Optional<PiesatRoleInfoDTO> dto = piesatRoleInfoDAO.findById(id);
        return dto.get();
    }

    @Override
    public Map<String, Object> list(Pageable pageable, RoleSearchVO searchDTO) {
        Page<PiesatRoleInfoDTO> page = piesatRoleInfoDAO.findAll(new Specification<PiesatRoleInfoDTO>() {
            @Override
            public Predicate toPredicate(Root<PiesatRoleInfoDTO> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                String name = searchDTO.getName();
                if (StringUtils.isNotBlank(name)) {
                    name = "%" + name + "%";
                    predicates.add(criteriaBuilder.like(root.get("name"),name));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        },pageable);
        return PageUtil.getPage(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> addAuthorizeMenu(AuthorizeMenuVO authorizeMenuDTO) {
        String roleId = authorizeMenuDTO.getRoleId();
        //根据角色id删除角色菜单关系
        piesatRoleMenuDAO.deleteByRoleId(roleId);
        List<String> menuList = authorizeMenuDTO.getMenuList();
        Map<String,String> resultMap = new HashMap<>();
        List<PiesatRoleMenuDTO> list = new ArrayList<>();
        for(String menuId:menuList){
            PiesatRoleMenuDTO piesatRoleMenuDTO = new PiesatRoleMenuDTO();
            piesatRoleMenuDTO.setMenuId(menuId);
            piesatRoleMenuDTO.setRoleId(roleId);
            list.add(piesatRoleMenuDTO);
        }
        piesatRoleMenuDAO.saveAll(list);
        resultMap.put("success","true");
        resultMap.put("message","添加成功");
        return resultMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> deleteOne(String id) {
        Map<String,String> resultMap = new HashMap<>();
        List<PiesatRoleMenuDTO> roleMenuList = piesatRoleMenuDAO.findByRoleId(id);
        if(roleMenuList != null && roleMenuList.size() >0){
            resultMap.put("success","false");
            resultMap.put("message","该角色下已绑定菜单，不能删除");
            return resultMap;
        }
        List<PiesatRoleResourceDTO> roleResourceList = piesatRoleResourceDAO.findByRoleId(id);
        if(roleResourceList != null && roleResourceList.size() > 0){
            resultMap.put("success","false");
            resultMap.put("message","该角色下已绑定按钮和路由，不能删除");
            return resultMap;
        }
        piesatRoleInfoDAO.deleteById(id);
        piesatRoleUserDAO.deleteByRoleId(id);
        resultMap.put("success","true");
        resultMap.put("message","删除成功");
        return resultMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> addAuthorizeResource(AuthorizeResourceVO authorizeResourceVO) {
        String roleId = authorizeResourceVO.getRoleId();
        String type = authorizeResourceVO.getType();
        String menuId = authorizeResourceVO.getMenuId();
        //往redis修改和存储资源路由和角色关系
        List<String> newResourceList = authorizeResourceVO.getResourceList();
        List<String> oldResourceList = piesatRoleResourceDAO.findByRoleIdAndTypeAndMenuId(roleId,type,menuId)
                .stream()
                .map(p -> p.getResourceId())
                .collect(toList());
        // 需要被删掉的
        List<String> reduce1 = oldResourceList.stream().filter(item -> !newResourceList.contains(item)).collect(toList());
        // 需要被增加的
        List<String> reduce2 = newResourceList.stream().filter(item -> !oldResourceList.contains(item)).collect(toList());
        Optional<PiesatRoleInfoDTO> piesatRoleInfoDTO = piesatRoleInfoDAO.findById(roleId);
        String mark = piesatRoleInfoDTO.get().getMark();
        List<String> delUrlList = piesatResourceInfoDAO.findAllById(reduce1)
                .stream()
                .filter(a ->a.getType().equals("interface"))
                .map(p ->p.getResource())
                .collect(toList());
        List<String> addUrlList = piesatResourceInfoDAO.findAllById(reduce2)
                .stream()
                .filter(a ->a.getType().equals("interface"))
                .map(p ->p.getResource())
                .collect(toList());

        Jedis jedis = JedisUtils.getJedis();
        if(jedis !=null){
            try{
                Map<String, String> map = jedis.hgetAll("auth:resourceRoles");
                for(String delUrl: delUrlList){
                    if(map.containsKey(delUrl)){

//                        List<String> markList = JSONObject.parseArray(map.get(delUrl),String.class);
                        JSONObject jsonObject = JSONObject.parseObject(map.get(delUrl));
                        List<String> markList = (List<String>) jsonObject.get("markList");
                        String redisMark = "ROLE_"+mark;
                        boolean boo = markList.contains(redisMark);
                        if(boo){
                            markList.remove(redisMark);
                        }
                        jsonObject.put("markList",markList);
                        String newValue = JSONObject.toJSONString(jsonObject);
                        jedis.hset("auth:resourceRoles",delUrl,newValue);
                    }
                }
                for(String addUrl : addUrlList){
                    List<String> markList = new ArrayList<>();
                    JSONObject jsonObject = new JSONObject();
                    if(map.containsKey(addUrl)){
                        jsonObject = JSONObject.parseObject(map.get(addUrl));
//                        markList = JSONObject.parseArray(map.get(addUrl),String.class);
                        markList = (List<String>) jsonObject.get("markList");
                    }
                    String redisMark = "ROLE_"+mark;
                    boolean boo = markList.contains(redisMark);
                    if(!boo){
                        markList.add(redisMark);
                    }
                    String newValue = "";
                    PiesatResourceInfoDTO piesatResourceInfoDTO = piesatResourceInfoDAO.findByResource(addUrl);
                    String name = piesatResourceInfoDTO.getName();
                    jsonObject.put("name",name);
                    if(markList !=null){
                        jsonObject.put("markList",markList);
                        newValue = JSONObject.toJSONString(jsonObject);
                    }else{
                        newValue = "";
                    }
                    jedis.hset("auth:resourceRoles",addUrl,newValue);
                }
            }finally {
                jedis.close();
            }
        }

        //根据角色id和类型删除角色资源关系
        piesatRoleResourceDAO.deleteByRoleIdAndType(roleId,type,menuId);

        Map<String,String> resultMap = new HashMap<>();
        List<PiesatRoleResourceDTO> list = new ArrayList<>();
        for(String resourceId:newResourceList){
            PiesatRoleResourceDTO piesatRoleResourceDTO = new PiesatRoleResourceDTO();
            piesatRoleResourceDTO.setResourceId(resourceId);
            piesatRoleResourceDTO.setRoleId(roleId);
            list.add(piesatRoleResourceDTO);
        }
        piesatRoleResourceDAO.saveAll(list);
        resultMap.put("success","true");
        resultMap.put("message","添加成功");
        return resultMap;
    }

    @Override
    public JSONArray findMenuListByRoleId(String roleId) {
        List<String> list = piesatRoleMenuDAO.findByRoleId(roleId)
                .stream()
                .map(p ->p.getMenuId())
                .collect(Collectors.toList());
        JSONArray menuArray = JSON.parseArray(JSON.toJSONString(list));
        return menuArray;
    }

    @Override
    public JSONArray findResourceListByRoleId(String roleId) {
        List<String> list = piesatRoleResourceDAO.findByRoleId(roleId)
                .stream()
                .map(p ->p.getResourceId())
                .collect(Collectors.toList());
        JSONArray menuArray = JSON.parseArray(JSON.toJSONString(list));
        return menuArray;
    }

    @Override
    public List<RoleUrlProjectionVO> listRoleUrl() {
        return piesatRoleResourceDAO.listRoleUrl();
    }

    @Override
    public List<PiesatRoleInfoDTO> findAll() {
        List<PiesatRoleInfoDTO> list = piesatRoleInfoDAO.findAll();
        return list;
    }
}
